#ifndef xpack_macro_xtypeid
#define xpack_macro_xtypeid
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::macro_xtypeid::inc
#include"define/base_type.hpp"
#include"define/classify.hpp"
#include"lang/cxx/private/l_is_secret.hpp"
#include"macro/xexport.hpp"
#include"macro/xmaybe_unused.hpp"
#include"meta/is_belong_to.hpp"
#include"meta/is_member_ptr.hpp"
#include"meta/is_class.hpp"
#include"meta/is_same.hpp"
#include"meta/origin_of.hpp"
#include"meta_seq/tlist.hpp"
#include"meta_seq/vlist.hpp"
#include"utils/static_length_of.hpp"
#pragma pop_macro("xuser")

namespace mixc::macro_xtypeid{
    using namespace inc;

    struct __dummy{};

    struct typeid_info{
        uxx     index               : sizeof(uxx) * 8 - 1;
        uxx     is_last_argument    : 1;
    };

    template<class callback_t>
    concept can_with_two_argument = requires(callback_t callback, f64 a0, f32 a1, ixx a2, uxx a3, asciis a4, bool a5){
        callback("key", a0); callback("key", a1); callback("key", a2); callback("key", a3); callback("key", a4); callback("key", a5);
    };

    template<class callback_t>
    concept can_with_three_argument = requires(callback_t callback, f64 a0, f32 a1, ixx a2, uxx a3, asciis a4, bool a5, typeid_info info){
        callback("key", a0, info); callback("key", a1, info); callback("key", a2, info); callback("key", a3, info); callback("key", a4, info); callback("key", a5, info);
    };

    template<class callback_t>
    concept can_with_two_argument_u = requires(callback_t callback, f64 a0, f32 a1, ixx a2, uxx a3, asciis a4, bool a5){
        callback(u"key", a0); callback(u"key", a1); callback(u"key", a2); callback(u"key", a3); callback(u"key", a4); callback(u"key", a5);
    };

    template<class callback_t>
    concept can_with_three_argument_u = requires(callback_t callback, f64 a0, f32 a1, ixx a2, uxx a3, asciis a4, bool a5, typeid_info info){
        callback(u"key", a0, info); callback(u"key", a1, info); callback(u"key", a2, info); callback(u"key", a3, info); callback(u"key", a4, info); callback(u"key", a5, info);
    };

    template<class callback_t>
    concept is_utf8_name = can_with_two_argument<callback_t> or can_with_three_argument<callback_t>;

    template<class callback_t>
    concept is_utf16_name = can_with_two_argument_u<callback_t> or can_with_three_argument_u<callback_t>;

    template<class type_t, class dummy_t> struct __typeid;
    template<class type_t>
    struct __typeid<type_t, __dummy> {
        using the_type = origin_of<type_t>;

        union{
            operator asciis() const {
                #define xgen(target)      else if constexpr (is_same<type_t, target>){ return # target; }
                if constexpr (is_class<the_type>){
                    auto name = the_type::__my_name;
                    return name;
                }

                xgen(char)
                xgen(char *)
                xgen(u08)
                xgen(u08p)
                xgen(u16)
                xgen(u16p)
                xgen(u32)
                xgen(u32p)
                xgen(u64)
                xgen(u64p)
                xgen(i08)
                xgen(i08p)
                xgen(i16)
                xgen(i16p)
                xgen(i32)
                xgen(i32p)
                xgen(i64)
                xgen(i64p)
                xgen(f32)
                xgen(f32p)
                xgen(f64)
                xgen(f64p)
                xgen(asciis)
                xgen(void)
                else{
                    return "unkown typeid";
                }
                #undef  xgen
            }

            auto operator ()() const {
                return operator asciis();
            }
        }name;
    };

    // 注意：
    // 不使用全局 thread_local，因为回调函数会可能再次进入 foreach_fields
    // inline thread_local uxx             l_i_field;

    template<class type_t, class dummy_t>
    struct __typeid : __typeid<type_t, __dummy> {
        // 不会跳过标记为 secret_type 的成员
        template<class callback_t>
        requires(is_utf8_name<callback_t> or is_utf16_name<callback_t>)
        static void foreach_fields(type_t const & value, callback_t const & call){
            foreach_fields_core<true>(value, call);
        }

        // 会递归跳过标记为 secret_type 的成员
        template<class callback_t>
        requires(is_utf8_name<callback_t> or is_utf16_name<callback_t>)
        static void foreach_fields_skip_secret(type_t const & value, callback_t const & call){
            if constexpr(inc::is_secret_type<type_t>){
                if (*inc::l_is_secret){
                    return;
                }
            }
            foreach_fields_core<false>(value, call);
        }

    private:
        template<bool is_non_secret_v, class callback_t>
        requires(is_utf8_name<callback_t> or is_utf16_name<callback_t>)
        static void foreach_fields_core(type_t const & value, callback_t const & call){
            using bl            = typename type_t::base_list;
            auto i_end          = inc::static_length_of(type_t::__my_field_name) - 1 - 1/*最后一个是 dummy 空串，实际的最后一个元素在倒数第二的位置*/;
            struct{
                uxx     i_field;
                voidp   end;
            } pair;

            pair.i_field        = 0;
            pair.end            = voidp(type_t::__my_field_name + i_end);
            (void)foreach_base<is_non_secret_v>(pair, bl{}, (type_t &)value, call);
        }

        template<class the_t, class field_t>
        static decltype(auto) get(the_t & self, field_t value){
            if constexpr (is_member_ptr<field_t>) {
                return self.*value;
            }
            else {
                return value->get(self);
            }
        }

        template<bool is_non_secret_v, class callback_t, class expand_t, class ... rest_base_t>
        static constexpr bool foreach_base(auto & pair, tlist<rest_base_t...>, expand_t & child, callback_t const & call){
            return // 返回，避免编译警告
                (... and foreach_base<is_non_secret_v>(pair, typename rest_base_t::base_list{}, (rest_base_t &)child/*二重里氏转换*/, call)) and // 先
                (foreach_base<is_non_secret_v>(pair, {}, child, call)); // 后
        }

        template<bool is_non_secret_v, class callback_t, class expand_t>
        static constexpr bool foreach_base(auto & pair, tlist<>, expand_t & child, callback_t const & call){
            using mlp           = typename expand_t::member_list_partial;
            return foreach_fields<is_non_secret_v>(tlist< mlp, mlp >{}, pair, child, call);
        }

        template<bool is_non_secret_v, class callback_t, class expand_t, class mlp_t, auto ... rest_field_ptr_v>
        static constexpr bool foreach_fields(
            tlist< mlp_t, vlist<rest_field_ptr_v...> >, 
            auto                                                              & pair, 
            expand_t                                                          & current, 
            callback_t                                                  const & call
        ){
            xmaybe_unused uxx i = 0; // 有误报
            return (... and foreach_fields<is_non_secret_v>(tlist< mlp_t, vlist<rest_field_ptr_v> >{}, i, pair, current, call));
        }

        template<bool is_non_secret_v, class callback_t, class expand_t, class mlp_t, auto field_ptr_v>
        static constexpr bool foreach_fields(
            tlist< mlp_t, vlist<field_ptr_v> >, 
            uxx                                                               & i,
            auto                                                              & pair, 
            expand_t                                                          & current, 
            callback_t                                                  const & call
        ){
            // 不是成员指针表示位域成员
            if constexpr (is_belong_to<expand_t, field_ptr_v> or not is_member_ptr<decltype(field_ptr_v)>){
                decltype(auto) value = get(current, field_ptr_v);
                using value_t = inc::origin_of<decltype(value)>;

                auto is_secret = inc::is_secret_type<value_t> and *inc::l_is_secret;
                auto invoke = [&](auto & value){
                    if constexpr (can_with_three_argument<callback_t>){
                        auto ti = typeid_info{ .index = pair.i_field, .is_last_argument = pair.end == voidp(expand_t::__my_field_name + i) };

                        if constexpr (is_utf8_name<callback_t>){
                            call(expand_t::__my_field_name[i], value, ti);
                        }
                        else{
                            call(expand_t::__my_field_name_u[i], value, ti);
                        }
                    }
                    else if constexpr(can_with_two_argument<callback_t>){
                        if constexpr (is_utf8_name<callback_t>){
                            call(expand_t::__my_field_name[i], value);
                        }
                        else{
                            call(expand_t::__my_field_name_u[i], value);
                        }
                    }
                    else{
                        static_assert(can_with_three_argument<callback_t> or can_with_two_argument<callback_t>);
                    }
                };

                if constexpr (is_non_secret_v){ // 第一优先级
                    if (is_secret){
                        invoke(secret_mark);
                    }
                    else{
                        invoke(value);
                    }
                }
                else if (not is_secret){ // 第二优先级
                    invoke(value);
                }
                // else 不打印
            }

            pair.i_field++;
            i++;
            return true;
        }
    };

    template<>
    struct __typeid<void, void> : __typeid<void, __dummy>{};
}

#define xtypeid(...)      mixc::macro_xtypeid::__typeid<__VA_ARGS__, void>()
#endif

xexport(mixc::macro_xtypeid::typeid_info)
